<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta http-equiv="cache-control" content="no-cache">
<title>Genivia - The WS-ReliableMessaging plugin</title>
<link href="genivia_tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css">
<link href="genivia_content.css" rel="stylesheet" type="text/css">
</head>
<body>
<div id="top">
 <div id="titlearea">
  <table height="72px" width="100%" cellspacing="0" cellpadding="0">
   <tbody>
    <tr>
     <td width="10%">&nbsp;</td>
     <td width="175px"><a href="https://www.genivia.com"><img alt="Genivia" src="GeniviaLogo2_trans_noslogan.png"/></a></td>
     <td class="tab_home"><a href="https://www.genivia.com">Home</a></td>
     <td class="tab_home"><a href="https://www.genivia.com/docs.html">Documentation</a></td>
     <td>
      <div style="float: right; font-size: 18px; font-weight: bold;">The WS-ReliableMessaging plugin</div>
      <br>
      <div style="float: right; font-size: 10px;">updated Sun Dec 9 2018 by Robert van Engelen</div>
     </td>
     <td width="10%">&nbsp;</td>
    </tr>
   </tbody>
  </table>
 </div>
<!-- Generated by Doxygen 1.8.11 -->
  <div id="navrow1" class="tabs">
    <ul class="tablist">
      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
      <li class="current"><a href="pages.html"><span>Related&#160;Pages</span></a></li>
      <li><a href="annotated.html"><span>Classes</span></a></li>
      <li><a href="files.html"><span>Files</span></a></li>
    </ul>
  </div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">The WS-ReliableMessaging plugin </div>  </div>
</div><!--header-->
<div class="contents">
<div class="toc"><h3>Table of Contents</h3>
<ul><li class="level1"><a href="#wsrm_1">WS-ReliableMessaging Setup</a></li>
<li class="level1"><a href="#wsrm_2">WS-ReliableMessaging Information Header Bindings</a></li>
<li class="level1"><a href="#wsrm_3">WS-ReliableMessaging Overview</a></li>
<li class="level1"><a href="#wsrm_4">Client-side Usage</a><ul><li class="level2"><a href="#wsrm_4_1">Creating, Closing, and Terminating Message Sequences</a></li>
<li class="level2"><a href="#wsrm_4_2">Creating a Sequence without an Offer</a></li>
<li class="level2"><a href="#wsrm_4_3">Exchanging Messages in a Sequence</a></li>
<li class="level2"><a href="#wsrm_4_4">Exchanging Messages with Acknowledgements in a Sequence</a></li>
<li class="level2"><a href="#wsrm_4_5">Resending Non-Acknowledged Messages</a></li>
<li class="level2"><a href="#wsrm_4_6">Relaying Response and Fault Messages with WS-Addressing</a></li>
<li class="level2"><a href="#wsrm_4_7">Using Retry Loops to Improve Robustness of Message Sends</a></li>
<li class="level2"><a href="#wsrm_4_8">Example Client</a></li>
</ul>
</li>
<li class="level1"><a href="#wsrm_5">Server-side Usage</a><ul><li class="level2"><a href="#wsrm_5_1">Setting up a WS-RM Destination Service</a></li>
<li class="level2"><a href="#wsrm_5_2">Handling Duplex Callback Service Operations</a></li>
</ul>
</li>
<li class="level1"><a href="#wsrm_6">WS-ReliableMessaging over HTTPS with Basic Authentication</a></li>
<li class="level1"><a href="#wsrm_7">WS-ReliableMessaging over UDP with Timeouts</a></li>
<li class="level1"><a href="#wsrm_8">WS-ReliableMessaging and WS-Security</a></li>
<li class="level1"><a href="#wsrm_9">The wsrm Plugin and C++ Proxy and Server Objects</a></li>
<li class="level1"><a href="#wsrm_10">Speed improvements with large number of sequences</a></li>
</ul>
</div>
<div class="textblock"><h1><a class="anchor" id="wsrm_1"></a>
WS-ReliableMessaging Setup</h1>
<p>The material in this section relates to the WS-ReliableMessaging and WS-Addressing (2005) specifications.</p>
<p>To use the wsrm plugin:</p><ol type="1">
<li>Run <code>wsdl2h -b -t typemap.dat</code> on a WSDL of a service that requires WS-ReliableMessaging and WS-Addressing headers. The typemap.dat file included in the gSOAP package is used to recognize and translate header blocks. The <code>-b</code> option ensures that one-way response message operations are added for duplex communications that require a client-side callback service.</li>
<li>Run <code>soapcpp2 -a</code> on the header file produced by wsdl2h. To enable reliable-messaging and addressing-based service operation selection, you MUST use soapcpp2 option <code>-a</code>. This allows the service to dispatch methods based on the WS-Addressing action information header value (when the wsa plugin is registered).</li>
<li>(Re-)compile and link stdsoap2.c/pp or libgsoap, (dom.c/pp when needed), <a class="el" href="wsrmapi_8c.html">plugin/wsrmapi.c</a>, <a class="el" href="wsaapi_8c.html">plugin/wsaapi.c</a>, <a class="el" href="duration_8c.html">custom/duration.c</a>, and the soapcpp2- generated source files.</li>
<li>Use the wsrm plugin API functions described below. The wsrm plugin uses the wsa plugin to implement the WS-Addressing 2005 operations. Both must be registered. The wsrm plugin API is self-contained. There is no need to use the wsa plugin API, unless WS-Addressing-specific headers must be added to messages.</li>
<li>For WCF compatibility and interoperability, compile <a class="el" href="wsrmapi_8c.html">wsrmapi.c</a> with compiler flag <code>-DWITH_WCF</code> for enhanced WCF compatibility and use compiler flag <code>-DWITH_WCF_SIM</code> to enable simulated WCF features channel instance and netrm BufferRemaining.</li>
</ol>
<p>An example wsrm client/server application can be found in samples/wsrm.</p>
<p>A gSOAP service definitions header file with an <code>#import "wsrm.h"</code> to support WS-ReliableMessaging 1.1 or <code>#import "wsrm5.h"</code> to support WS-ReliableMessaging 1.0 (2005). The imports are automatically generated by wsdl2h for a set of WSDLs that use WS-ReliableMessaging as per WS-Policy. The wsdl2h-generated header file should be further processed by soapcpp2 to generate the binding code. The <a class="el" href="wsrmapi_8h.html">wsrmapi.h</a> and <a class="el" href="wsrmapi_8c.html">wsrmapi.c</a> implement the WS-ReliableMessaging API described in this document.</p>
<p>A wsdl2h-generated service definitions header file might include the following imports, where the <a class="el" href="wsrm_8h.html">wsrm.h</a> is mandatory to support WS-ReliableMessaging:</p>
<div class="fragment"><div class="line"><span class="preprocessor">#import &quot;soap12.h&quot;</span></div><div class="line"><span class="preprocessor">#import &quot;<a class="code" href="wsrm_8h.html">wsrm.h</a>&quot;</span></div></div><!-- fragment --><p>The <a class="el" href="wsrm_8h.html">wsrm.h</a> header file is imported from <a class="el" href="wsrm_8h.html">import/wsrm.h</a> by soapcpp2. The <a class="el" href="wsrm_8h.html">wsrm.h</a> import can be manually added to enable WS-ReliableMessaging when needed. The gSOAP service definitions header file is processed with soapcpp2 to generate the client-side and/or server-side binding code.</p>
<p>Note that the <a class="el" href="wsrm_8h.html">wsrm.h</a> and the WS-ReliableMessaging-dependent <a class="el" href="wsrx_8h.html">wsrx.h</a> and <a class="el" href="wsa5_8h.html">wsa5.h</a> header files are located in the import directory of the gSOAP package. These files define the WS-ReliableMessaging and WS-Addressing information header elements and types. The <a class="el" href="wsrx_8h.html">wsrx.h</a> header file defines the WS-ReliableMessaging CreateSequence, CloseSequence, and TerminateSequence operations, as well as an one-way SequenceAcknowledgement operation to accept acknowledgements. The soap12.h header file enables SOAP 1.2 messaging.</p>
<p>For developers working on protocols: the WS-ReliableMessaging header blocks in <a class="el" href="wsrm_8h.html">wsrm.h</a> were generated from the WS-ReliableMessaging schema with the wsdl2h tool and WS/WS-typemap.dat as follows: </p><pre class="fragment">wsdl2h -cgyex -o wsrm.h -t WS/WS-typemap.dat WS/WS-ReliableMessaging.xsd
</pre><p>This step is not needed to use the wsrm plugin.</p>
<h1><a class="anchor" id="wsrm_2"></a>
WS-ReliableMessaging Information Header Bindings</h1>
<p>To associate WS-ReliableMessaging and WS-Addressing information headers with service operations, the SOAP Header struct <code><a class="el" href="struct_s_o_a_p___e_n_v_____header.html" title="Added. ">SOAP_ENV__Header</a></code> must have been declared and contain the necessary header blocks to be transported with SOAP messages. The <code><a class="el" href="struct_s_o_a_p___e_n_v_____header.html" title="Added. ">SOAP_ENV__Header</a></code> for WS-ReliableMessaging and WS-Addressing is predefined in <a class="el" href="wsrm_8h.html">wsrm.h</a> and imported into the gSOAP service definitions header file (this is automatically generated by wsdl2h). For each service operation in the gSOAP service definitions header file that uses WS-ReliableMessaging and/or WS-Addressing method-header-part directives are used.</p>
<p>For example, the following gSOAP service definitions header file illustrates a typical import and service operation definition of operation 'example' in service namespace 'ns':</p>
<div class="fragment"><div class="line"><span class="preprocessor">#import &quot;<a class="code" href="wsrm_8h.html">wsrm.h</a>&quot;</span></div><div class="line"></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsa5__MessageID</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsa5__RelatesTo</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsa5__From</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsa5__ReplyTo</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsa5__FaultTo</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsa5__To</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsa5__Action</span></div><div class="line"></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsrm__Sequence</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsrm__AckRequested</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: example wsrm__SequenceAcknowledgement</span></div><div class="line"></div><div class="line"><span class="comment">//gsoap ns service method-action:          example urn:example/examplePort/example</span></div><div class="line"><span class="comment">//gsoap ns service method-output-action:   example urn:example/examplePort/exampleResponse</span></div><div class="line"></div><div class="line"><span class="keywordtype">int</span> ns__example(<span class="keywordtype">char</span> *in, <span class="keyword">struct</span> ns__exampleResponse { <span class="keywordtype">char</span> *out; } *);</div></div><!-- fragment --><p>The wsa5 information headers are defined in <a class="el" href="wsa5_8h.html">wsa5.h</a> and imported by <a class="el" href="wsrm_8h.html">wsrm.h</a> (both are located in the 'import' directory). Here, all of the WS-Addressing and WS-ReliableMessaging information headers are bound to the ns__example operation request and response messages.</p>
<p>The method action directive is important for WS-Addressing, because WS-Addressing Action information headers must be included that are unique for each operation. The soapcpp2 option <code>-a</code> ensures that WS-Addressing Action header blocks (and HTTP Action headers) are processed at the receiving side, which means that the service dispatcher uses the Action together with the operation name to invoke the service operation at the destination. This also means that Action headers must be properly set by the client.</p>
<p>Note: the <code><a class="el" href="struct_s_o_a_p___e_n_v_____header.html" title="Added. ">SOAP_ENV__Header</a></code> struct can be declared in multiple files. The soapcpp2 tool gathers all members of the structs into the "final" <code><a class="el" href="struct_s_o_a_p___e_n_v_____header.html" title="Added. ">SOAP_ENV__Header</a></code> struct used by the gSOAP engine and your application. This is convenient when service-specific header blocks are combined with WS-ReliableMessaging and WS-Addressing header blocks or when WS-Security header blocks are added by the WSSE plugin.</p>
<h1><a class="anchor" id="wsrm_3"></a>
WS-ReliableMessaging Overview</h1>
<p>In this section a brief overview of WS-ReliableMessaging is given. For more details please refer to the WS-ReliableMessaging protocol or tutorials on the subject. The following introduces the basic concepts of WS-ReliableMessaging from a practical point of view.</p>
<p>WS-ReliableMessaging is useful to improve the reliability of one-way asynchronous messaging, for unreliable data gram messaging (SOAP-over-UDP), or to improve reliable delivery of responses relayed to other destinations, such as response messages that are relayed to destinations indicated by the WS-Addressing ReplyTo header. The protocol is also useful when multiple sources are sending messages that arrive out of order or must be flagged as an incomplete message collection when messages are missing as defined by the notion of a collection of related messages. Messages delivered out-of-order are not internally reordered automatically. The application logic should be designed to be robust to out-of-order delivery effects, for example by using a vector to collect the data elements received before the data is processed. Alternatively, the server-side <code>soap_wsrm_check_and_wait</code> calls can be used to let the current thread wait until preceding messages have been received and processed (by other threads). For single-thread processing with keep-alive, this will cause a performance bottleneck unless the message queue plugin is used. The message queue plugin (<a class="el" href="mq_8c.html">mq.c</a>) provides an approach to buffer inbound messages for in-order processing.</p>
<p>WS-ReliableMessaging is not essential to improve the reliability of request-response message exchanges between two parties over HTTP, since a successful delivery of a request message can be inferred from the fact that a response was received for the request sent.</p>
<p>WS-ReliableMessaging "protects" message sequences, i.e. a collection of related messages. A WS-ReliableMessaging message sequence is created after which the sequence of messages is sent. The sequence is closed and terminated by the client after the last message. Either the message sequence is complete or not, and the resulting action to discard the incomplete message sequence or not depends on the chosen behavior. Duplicate messages (e.g. resulting from resends) are always discarded.</p>
<p>To create a new sequence, a client (WS-RM source) requests from the server (WS-RM destination) a unique (new) message sequence identification. The server responds with the identification to be used as well as other details, such as the expiration time of the sequence and the behavior implemented when a sequence was received incomplete:</p>
<ul>
<li>NoDiscard means that the sequence of messages is not discarded by the destination server when one or more messages are missing (or unacknowledged). That is, no acknowledged messages in the sequence will be discarded. The WS-RM plugin will reorder messages either by ignoring any out-of-order messages (when calling <code>soap_wsrm_check</code>) or wait for out-of-order messages to arrive in a timeout window (when calling <code>soap_wsrm_check_and_wait</code>).</li>
<li>DiscardFollowingFirstGap means that the initial messages of the sequence are retained by the destination up to the first gap (a missing message) in the sequence. Does not allow for out-of-order message delivery.</li>
<li>DiscardEntireSequence means that the entire sequence of messages will be discarded when there are one or more gaps (messages are missing). With the WS-RM plugin, messages may be accepted out-of-order.</li>
</ul>
<p>When the client terminates the sequence, it first sends a sequence close request (or a last message with the older WS-RM 1.0) and then a sequence termination request to the destination server. The sequence close informs the server how many messages should have been received. The client can still resend messages after the close, but no new messages are supposed to be send. After the optional resends, the client requests termination of the sequence. The termination will be successful depending on the behavior when messages went missing, as was listed above.</p>
<p>The ensure reliable delivery, the WS-ReliableMessaging protocol allows the client to resend messages. Message resends are desirable when messages are lost in transit. Since the client has limited information on delivery success (message delivery acknowledgments can get lost as well), the client may resend more messages than necessary. This could lead to message duplication. However, messages that were already received by the server are discarded.</p>
<p>The client may request message delivery acknowledgements from the server. The server sends message receipt acknowledgements for all the messages it has received in the sequence back to the client, usually by piggy-backing them with the response of a subsequent message exchange. When the client is informed about successful delivery it reduces the number of resends the client will attempt.</p>
<p>Messages in a sequence are uniquely identified by their enumeration number in the sequence. Messages may be transmitted out of order. A missing message number indicates a gap in the message sequence. Message receipt acknowledgements consist of ranges of message numbers. Acknowledgements are normally sent to the source to help identify which messages should be resend.</p>
<p>With the WS-Addressing protocol, message responses and fault messages can be relayed to other destinations. The ReplyTo and FaultTo WS-Addressing header blocks are used for this purpose. The WS-ReliableMessaging protocol allows message acknowledgements to be relayed. The WS-ReliableMessaging AcksTo header block is used for this purpose.</p>
<p>In all, there are four types of communicating peers that are visible to the source (the client):</p>
<ul>
<li>The destination service. The WS-ReliableMessaging sequence is essentially controlled by this service. When a message is sent by the source to the destination service (over HTTP, TCP, or UDP), the WS-Addressing To information header may contain the endpoint address. The destination service normally returns message responses back to the client (HTTP request-response) or in duplex mode with one-way messages.</li>
<li>Optionally, one of more ReplyTo destination services that accept response messages from the destination service. Rather than sending responses back to the client, the destination service relays them to another service. The WS-Addressing ReplyTo information header is used by the client to indicate the response relay target.</li>
<li>Optionally, one or more FaultTo destination services that accept SOAP fault messages from the destination service. Rather than sending SOAP Faults back to the client, the destination service relays them to another service. The WS-Addressing FaultTo information header is used by the client to indicate the fault relay target.</li>
<li>Optionally, one AcksTo destination service that accept WS-ReliableMessaging acknowledgements. Rather than sending acknowledgements piggy-backed with response messages back to the client, the destination service relays them to another service. The WS-ReliableMessaging AcksTo information header is used by the client when the sequence is created to indicate the acknowledgements relay target. The AcksTo cannot be changed after sequence creation to termination.</li>
</ul>
<p>The destination service normally serves as ReplyTo, FaultTo, and AcksTo service, which is the default scenario with request-response message exchanges. Replies, faults, and acknowledgements can also be asynchroniously transmitted in duplex mode. In that case, the WS-RM source client acts as a callback service to accept messages on a port.</p>
<p>The practical aspects of message sequence creation, the message exchanges, the message relays, and sequence close/termination are presented for the client side first and then for each of the four types of destination servers.</p>
<h1><a class="anchor" id="wsrm_4"></a>
Client-side Usage</h1>
<h2><a class="anchor" id="wsrm_4_1"></a>
Creating, Closing, and Terminating Message Sequences</h2>
<p>A sequence is created, closed, terminated, and cleaned-up on the client side as follows, using a 'soap' context struct (use one 'soap' context per thread):</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>soap *soap = soap_new(); <span class="comment">// Note: can use C++ proxy instead of &#39;soap&#39;</span></div><div class="line">soap_register_plugin(soap, <a class="code" href="wsaapi_8h.html#aa013e3760b97c2efcc71d29b57394501">soap_wsa</a>);</div><div class="line">soap_register_plugin(soap, <a class="code" href="wsrmapi_8h.html#a3ca1614f5da3589a41957cb2f93394dc">soap_wsrm</a>);</div><div class="line"></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *destination = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// WS-RM destination server address</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *source = NULL;       <span class="comment">// WS-RM source (NULL means current)</span></div><div class="line">ULONG64 expires = 10000;         <span class="comment">// 10000 ms to expire (10 seconds)</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *<span class="keywordtype">id</span> = NULL;           <span class="comment">// id = NULL: generate a temp sequence ID</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *opt_msg_id = NULL;   <span class="comment">// WS-Addressing message ID (optional)</span></div><div class="line"></div><div class="line"><a class="code" href="structsoap__wsrm__sequence.html">soap_wsrm_sequence_handle</a> seq;   <span class="comment">// a local handle to the sequence state</span></div><div class="line"></div><div class="line"><span class="comment">// Step 1: create a sequence</span></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a54cb27e4c3139e5197a30d15686cadca">soap_wsrm_create_offer</a>(soap, destination, source, <span class="keywordtype">id</span>, expires, <a class="code" href="wsrm_8h.html#aff9cd7eafbe766f7c92b26f868cb0418a1a5ed0390b355179aad4c5e99024a1e1">NoDiscard</a>, opt_msg_id, &amp;seq))</div><div class="line">{</div><div class="line">  <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">  ... <span class="comment">// error creating sequence</span></div><div class="line">} </div><div class="line"></div><div class="line"><span class="comment">// Step 2: exchange messages with WS-RM destination, request acks, receive acks, issue resends (see later) </span></div><div class="line">...</div><div class="line"></div><div class="line"><span class="comment">// Step 3: optionally close first before terminating</span></div><div class="line">if (<a class="code" href="wsrmapi_8h.html#a663e39e46e4fb291ee0f9af8a0badac5">soap_wsrm_close</a>(soap, seq, NULL))</div><div class="line">{</div><div class="line">  <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">  ... <span class="comment">// error closing sequence</span></div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// Step 4: optionally resend messages before terminating</span></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a5a6aec6d79f12deef6b60e878a7c3dc9">soap_wsrm_nack</a>(seq)) <span class="comment">// any non-acks for messages sent?</span></div><div class="line">  <a class="code" href="wsrmapi_8h.html#af0644e93628d1c450cb3c73fed5afd4f">soap_wsrm_resend</a>(soap, seq, 0, 0); <span class="comment">// resend all non-acked messages</span></div><div class="line"></div><div class="line"><span class="comment">// Step 5: terminate</span></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#aed55a951561e63b74699003f423e6e4d">soap_wsrm_terminate</a>(soap, seq, NULL))</div><div class="line">{</div><div class="line">  <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">  ... <span class="comment">// error creating sequence</span></div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// Step 6: cleanup</span></div><div class="line"><a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div></div><!-- fragment --><p>For duplex communication, the responses are sent to the WS-RM source's port, to which we need to listen via a callback service. There are two ways to do so, by polling or by running a separate threat that accepts responses. In the code below we use a polling approach to process responses sent asynchronously to the WS-RM source:</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>soap *soap = soap_new(); <span class="comment">// Note: can use C++ proxy instead of &#39;soap&#39;</span></div><div class="line">soap_register_plugin(soap, <a class="code" href="wsaapi_8h.html#aa013e3760b97c2efcc71d29b57394501">soap_wsa</a>);</div><div class="line">soap_register_plugin(soap, <a class="code" href="wsrmapi_8h.html#a3ca1614f5da3589a41957cb2f93394dc">soap_wsrm</a>);</div><div class="line"></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *destination = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// WS-RM destination server address</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *source = <span class="stringliteral">&quot;...&quot;</span>;      <span class="comment">// WS-RM source address destination sends to</span></div><div class="line"><span class="keywordtype">int</span> source_port = ...;           <span class="comment">// port of WS-RM source address</span></div><div class="line">ULONG64 expires = 10000;         <span class="comment">// 10000 ms to expire (10 seconds)</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *<span class="keywordtype">id</span> = NULL;           <span class="comment">// id = NULL: generate a temp sequence ID</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *opt_msg_id = NULL;   <span class="comment">// WS-Addressing message ID (optional)</span></div><div class="line"><span class="keywordtype">int</span> retry;</div><div class="line"></div><div class="line"><a class="code" href="structsoap__wsrm__sequence.html">soap_wsrm_sequence_handle</a> seq;   <span class="comment">// a local handle to the sequence state</span></div><div class="line"></div><div class="line"><span class="keyword">struct </span>soap *callback = soap_new(); <span class="comment">// callback for polling</span></div><div class="line"></div><div class="line"><span class="comment">// Step 1: create a WS-RM source port binding for the callback to poll messages</span></div><div class="line"><span class="keywordflow">if</span> (!soap_valid_socket(soap_bind(callback, NULL, source_port, 100)))</div><div class="line">  ... <span class="comment">// error</span></div><div class="line"></div><div class="line"><span class="comment">// Step 2: create a sequence</span></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a54cb27e4c3139e5197a30d15686cadca">soap_wsrm_create_offer</a>(soap, destination, source, <span class="keywordtype">id</span>, expires, <a class="code" href="wsrm_8h.html#aff9cd7eafbe766f7c92b26f868cb0418a1a5ed0390b355179aad4c5e99024a1e1">NoDiscard</a>, opt_msg_id, &amp;seq))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error != 202) <span class="comment">// Error != HTTP Accepted</span></div><div class="line">  {</div><div class="line">    <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">    ... <span class="comment">// error creating sequence</span></div><div class="line">  }</div><div class="line">}</div><div class="line"><span class="comment">// poll 10 times for 1 second until the sequence created response received</span></div><div class="line"><span class="keywordflow">for</span> (retry = 10; retry &amp;&amp; !<a class="code" href="wsrmapi_8h.html#a9029b22721a4b39c0c7ef22b53de0900">soap_wsrm_seq_created</a>(soap, seq); retry--)</div><div class="line">  <span class="keywordflow">if</span> (callback_poll(callback, 1)) <span class="comment">// 1 second poll</span></div><div class="line">    ... <span class="comment">// error</span></div><div class="line"><span class="keywordflow">if</span> (!retry)</div><div class="line">  ... <span class="comment">// error</span></div><div class="line"></div><div class="line"><span class="comment">// Step 3: exchange messages with WS-RM destination, request acks, receive acks, issue resends, and poll (see later) </span></div><div class="line">...</div><div class="line"></div><div class="line"><span class="comment">// Step 4: optionally close first before terminating</span></div><div class="line">if (<a class="code" href="wsrmapi_8h.html#a663e39e46e4fb291ee0f9af8a0badac5">soap_wsrm_close</a>(soap, seq, NULL))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error != 202) <span class="comment">// Error != HTTP Accepted</span></div><div class="line">  {</div><div class="line">    <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">    ... <span class="comment">// error closing sequence</span></div><div class="line">  }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (callback_poll(callback, -500000)) <span class="comment">// 500 ms poll</span></div><div class="line">  ... <span class="comment">// error</span></div><div class="line"></div><div class="line"><span class="comment">// Step 5: optionally resend messages before terminating</span></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a5a6aec6d79f12deef6b60e878a7c3dc9">soap_wsrm_nack</a>(seq)) <span class="comment">// any nacks?</span></div><div class="line">{</div><div class="line">  <a class="code" href="wsrmapi_8h.html#af0644e93628d1c450cb3c73fed5afd4f">soap_wsrm_resend</a>(soap, seq, 0, 0); <span class="comment">// resend all non-acked messages</span></div><div class="line">  <span class="keywordflow">if</span> (callback_poll(callback, -100000)) <span class="comment">// 100 ms poll</span></div><div class="line">    ... <span class="comment">// error</span></div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// Step 6: terminate</span></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#aed55a951561e63b74699003f423e6e4d">soap_wsrm_terminate</a>(soap, seq, NULL))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error != 202) <span class="comment">// Error != HTTP Accepted</span></div><div class="line">  {</div><div class="line">    <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">    ... <span class="comment">// error creating sequence</span></div><div class="line">  }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// only needed with WS-RM 1.1 to accept terminate response</span></div><div class="line"><span class="keywordflow">if</span> (callback_poll(callback, -500000)) <span class="comment">// 500 ms poll</span></div><div class="line">  ... <span class="comment">// error</span></div><div class="line"></div><div class="line"><span class="comment">// Step 7: cleanup</span></div><div class="line"><a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div></div><!-- fragment --><p>The polling operation can be implemented as follows:</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> callback_poll(<span class="keyword">struct</span> soap *soap, <span class="keywordtype">int</span> timeout)</div><div class="line">{</div><div class="line">  <span class="keywordtype">int</span> poll = 5; <span class="comment">// 5 poll cycles times max, ensures make progress</span></div><div class="line">  soap-&gt;accept_timeout = timeout; <span class="comment">// polling timout</span></div><div class="line">  soap-&gt;recv_timeout = timeout;</div><div class="line">  soap-&gt;send_timeout = soap-&gt;recv_timeout = 1; <span class="comment">// 1 sec</span></div><div class="line">  <span class="keywordflow">while</span> (poll-- &amp;&amp; soap_valid_socket(soap_accept(soap)))</div><div class="line">  {</div><div class="line">    soap_serve(soap);</div><div class="line">    soap_destroy(soap);</div><div class="line">    soap_end(soap);</div><div class="line">  }</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error == SOAP_STOP || soap-&gt;error == SOAP_EOF) <span class="comment">// timed out</span></div><div class="line">    <span class="keywordflow">return</span> soap-&gt;error = SOAP_OK;</div><div class="line">  <span class="keywordflow">return</span> soap-&gt;error;</div><div class="line">}</div></div><!-- fragment --><p>In addition, callback service operations must be defined to handle faults and, when applicable, one-way message responses sent by the destination.</p>
<p>Fault messages are accepted by the callback and processed by the service operation that can be customized to your needs:</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> <a class="code" href="wsa5_8h.html#af1f0af3d70354401b6969aa0b689a5dc">SOAP_ENV__Fault</a>(<span class="keyword">struct</span> soap *soap, </div><div class="line">  _QName                   faultcode,             <span class="comment">// SOAP 1.1</span></div><div class="line">  <span class="keywordtype">char</span>                    *faultstring,           <span class="comment">// SOAP 1.1</span></div><div class="line">  <span class="keywordtype">char</span>                    *faultactor,            <span class="comment">// SOAP 1.1</span></div><div class="line">  <span class="keyword">struct</span> SOAP_ENV__Detail *detail,                <span class="comment">// SOAP 1.1</span></div><div class="line">  <span class="keyword">struct</span> SOAP_ENV__Code   *Code,                  <span class="comment">// SOAP 1.2</span></div><div class="line">  <span class="keyword">struct</span> SOAP_ENV__Reason *Reason,                <span class="comment">// SOAP 1.2</span></div><div class="line">  <span class="keywordtype">char</span>                    *Node,                  <span class="comment">// SOAP 1.2</span></div><div class="line">  <span class="keywordtype">char</span>                    *Role,                  <span class="comment">// SOAP 1.2</span></div><div class="line">  <span class="keyword">struct</span> SOAP_ENV__Detail *Detail                 <span class="comment">// SOAP 1.2</span></div><div class="line">)</div><div class="line">{</div><div class="line">  soap_send_empty_response(soap, 202);</div><div class="line">  <span class="keywordflow">if</span> (!detail)</div><div class="line">    detail = Detail;</div><div class="line">  <span class="keywordflow">if</span> (detail &amp;&amp; detail-&gt;__type == SOAP_TYPE__wsrm__Identifier)</div><div class="line">  {</div><div class="line">    <span class="comment">// the sequence id is in the Fault Detail __type and fault members</span></div><div class="line">    <span class="keywordtype">char</span> *<span class="keywordtype">id</span> = (<span class="keywordtype">char</span>*)detail-&gt;fault;</div><div class="line">    <span class="comment">// we opt to treat all faults fatal, so let&#39;s terminate the sequence</span></div><div class="line">    <a class="code" href="structsoap__wsrm__sequence.html">soap_wsrm_sequence_handle</a> seq = <a class="code" href="wsrmapi_8h.html#a5fa72f2f3d4c3124ff8bb9f8dea3ea0b">soap_wsrm_seq_lookup_id</a>(soap, <span class="keywordtype">id</span>);</div><div class="line">    <span class="keywordflow">if</span> (seq)</div><div class="line">    {</div><div class="line">      <a class="code" href="wsrmapi_8h.html#a8c2c3d3298b9695483f5562d9765e8cc">soap_wsrm_error</a>(soap, seq, <a class="code" href="wsrm_8h.html#a74a1b26ed97040d29fb3ad5b1e88a3c8a872df7276b73619abb24b3bf093da5f6">wsrm__SequenceTerminated</a>);</div><div class="line">      <a class="code" href="wsrmapi_8h.html#ad540da044ec72af0f94ffd6bd3a0026d">soap_wsrm_seq_release</a>(soap, seq);</div><div class="line">      <span class="keywordflow">return</span> soap-&gt;error;</div><div class="line">    }</div><div class="line">  }</div><div class="line">  <span class="keywordflow">return</span> SOAP_OK;</div><div class="line">}</div></div><!-- fragment --><p>This cleanup of memory resources may be performed at any time in the sequence of message exchange or afterwards when desired. The sequence state is maintained independent of these cleanup operations.</p>
<p>A graceful sequence termination may fail when the delivery of a sequence of messages is incomplete or when the lifetime of the sequence expired (the hard limit on the lifetime is <code>SOAP_WSRM_MAX_SEC_TO_EXPIRE</code>, this macro can be changed).</p>
<p>The WS-RM destination determines the failure based on the final sequence state and the sequence behavior. The behavior is set to NoDiscard by default, which means that the sequence is not discarded when transmission gaps appeared in the messages and the sequence is incomplete. The desired behavior can be specified with a sequence creation offer as explained in the next section.</p>
<p>If the source ReplyTo and AcksTo addresses differ in your project, then use the following:</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *destination = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// WS-RM destination server address</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *replyto = NULL;      <span class="comment">// WS-RM ReplyTo</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *acksto = NULL;       <span class="comment">// WS-RM AckstTo</span></div><div class="line">ULONG64 expires = 10000;         <span class="comment">// 10000 ms to expire (10 seconds)</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *<span class="keywordtype">id</span> = NULL;           <span class="comment">// id = NULL: generate a temp sequence ID</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *opt_msg_id = NULL;   <span class="comment">// WS-Addressing message ID (optional)</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a5289c0ff322a2a33ebfa18aba1c3647b">soap_wsrm_create_offer_acksto</a>(soap, destination, replyto, acksto, <span class="keywordtype">id</span>, expires, <a class="code" href="wsrm_8h.html#aff9cd7eafbe766f7c92b26f868cb0418aa8b0ffb8243f515937e5e229bb3d9be3">DiscardEntireSequence</a>, opt_msg_id, &amp;seq)))</div><div class="line">  ... <span class="comment">// error</span></div></div><!-- fragment --><p>Expiration times should not be infinite, because sequences are kept in memory until expired even when the sequences are closed and terminated. This permits the detection of duplicate sequences. The limit on the lifetime is <code>SOAP_WSRM_MAX_SEC_TO_EXPIRE</code>. This macro can be changed.</p>
<h2><a class="anchor" id="wsrm_4_2"></a>
Creating a Sequence without an Offer</h2>
<p>To enable a destination server to produce a reliable message response sequence, you need to create a sequence with an offer. Otherwise, response messages are not tracked and delivery is not verified. A sequence of two-way message exchanges should use the offer mechanism. If all messages are one-way from source to destination then the sequence offer mechanism is not needed. A sequence can be created without an offer as follows:</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *destination = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// WS-RM destination server address</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *source = NULL;       <span class="comment">// WS-RM source (NULL means current)</span></div><div class="line">ULONG64 expires = 10000;         <span class="comment">// 10000 ms to expire (10 seconds)</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *opt_msg_id = NULL;   <span class="comment">// WS-Addressing message ID (optional)</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#ae1351fd2ece8ddd1a8da40e7ebe6b36f">soap_wsrm_create</a>(soap, destination, source, expires, <a class="code" href="wsrm_8h.html#aff9cd7eafbe766f7c92b26f868cb0418aa8b0ffb8243f515937e5e229bb3d9be3">DiscardEntireSequence</a>, opt_msg_id, &amp;seq))</div><div class="line">  ... <span class="comment">// error</span></div></div><!-- fragment --><p>Expiration times should not be infinite, because sequences are kept in memory until expired even when the sequences are closed and terminated. This permits the detection of duplicate sequences. The limit on the lifetime is <code>SOAP_WSRM_MAX_SEC_TO_EXPIRE</code>. This macro can be changed.</p>
<h2><a class="anchor" id="wsrm_4_3"></a>
Exchanging Messages in a Sequence</h2>
<p>Each message exchange with the WS-RM destination should be preceded with a <code>soap_wsrm_request</code> or <code>soap_wsrm_request_acks</code> call to set the required WS-RM information headers for the message send operation or request-response exchange.</p>
<p>For example, consider the 'example' operation defined previously and suppose we invoke the 'example' operation in a sequence (after creation and before closing):</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *exampleRequestAction = <span class="stringliteral">&quot;urn:example/examplePort/example&quot;</span>;</div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *exampleRequestMessageID = NULL; <span class="comment">// optional WS-Addressing ID</span></div><div class="line"><span class="keyword">struct </span>ns__exampleResponse response;</div><div class="line"></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *endpoint = <a class="code" href="wsrmapi_8h.html#abd9ac0c9258d6f2210d767aeff3cbf51">soap_wsrm_to</a>(seq);</div><div class="line"><span class="keywordflow">if</span> (endpoint)</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a05857d4bed3b3052e6878f490330277f">soap_wsrm_request</a>(soap, seq, exampleRequestMessageID, exampleRequestAction))</div><div class="line">    ... <span class="comment">// error: out of memory</span></div><div class="line"></div><div class="line">  <span class="keywordflow">if</span> (soap_call_ns__example(soap, endpoint, exampleRequestAction, &amp;response))</div><div class="line">    soap_print_fault(soap, stderr); <span class="comment">// an error occurred</span></div><div class="line">  <span class="keywordflow">else</span></div><div class="line">    ... <span class="comment">// process the response</span></div><div class="line">}</div></div><!-- fragment --><p>To generate WS-Addressing message IDs, use <code>soap_wsa_rand_uuid</code>, for example:</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *exampleRequestAction = <span class="stringliteral">&quot;urn:example/examplePort/example&quot;</span>;</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a05857d4bed3b3052e6878f490330277f">soap_wsrm_request</a>(soap, seq, <a class="code" href="wsaapi_8h.html#ac2b81c42093fc9fcadcf86e7d801e03b">soap_wsa_rand_uuid</a>(soap), exampleRequestAction))</div><div class="line">  ... <span class="comment">// error: out of memory</span></div></div><!-- fragment --><p>The <code>soap_wsrm_request</code> takes the sequence handle and optional WS-Addressing message ID and mandatory WS-Addressing action string (this string must match the method-action defined in the gSOAP service definition header file). It produces a WS-RM header block with the message number incremented by one for the invocation. Messages are enumerated from one and included in the WS-RM header to allow the destination to determine which messages were received in the sequence (for acknowledgements) and to ignore duplicate messages.</p>
<p>The remote invocation <code>soap_call_ns__example</code> uses the endpoint provided by <code>soap_wsrm_to(seq)</code> for the WS-RM destination address, which was set by <code>soap_wsrm_create</code> or by <code>soap_wsrm_create_offer</code>. Because the address may change due to a redirect, we encourage the use of <code>soap_wsrm_to</code> for the WS-RM destination address. When used at the server side, <code>soap_wsrm_to(seq)</code> is the ReplyTo address provided by the client's request message, which may be none (NULL) for a one-way call. Therefore, it is wise to check the return value of <code>soap_wsrm_to(seq)</code>.</p>
<p>A C++ proxy object (generated by soapcpp2 option <code>-j</code>) that invokes a service operation should reset the destination address explicitly by setting the <code>soap_endpoint</code> member string before each operation invocation.</p>
<h2><a class="anchor" id="wsrm_4_4"></a>
Exchanging Messages with Acknowledgements in a Sequence</h2>
<p>Before sending a message, a WS-RM request should be issued using <code>soap_wsrm_request_acks</code>. This informs the WS-RM destination to return message delivery acknowledgements back to the sender (piggy-backed in the header of the response message), unless the AcksTo is set to target an acknowledgement service endpoint in which case the acknowledgements are sent to.</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a7292b4a8e24e767b538e0fb2993a6864">soap_wsrm_request_acks</a>(soap, seq, opt_msg_id, exampleRequestAction))</div><div class="line">  ... <span class="comment">// error</span></div><div class="line"><span class="keywordflow">if</span> (soap_call_ns__example(soap, endpoint, exampleRequestAction, &amp;response))</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error != 202) <span class="comment">// Error != HTTP Accepted</span></div><div class="line">    ... <span class="comment">// error</span></div></div><!-- fragment --><p>When duplex messaging is used via a callback, a polling operation will be needed afterwards:</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (callback_poll(callback, -500000)) <span class="comment">// 500 ms poll</span></div><div class="line">  ... <span class="comment">// error</span></div></div><!-- fragment --><p>The <code>soap_wsrm_close</code> returns acknowledgements automatically, so requesting intermediate acknowledgements is not required to issue a final <code>soap_wsrm_resend</code> to resend all non-acknowledged messages, e.g. after <code>soap_wsrm_close</code>. See also below.</p>
<h2><a class="anchor" id="wsrm_4_5"></a>
Resending Non-Acknowledged Messages</h2>
<p>All non-acknowledged messages in a sequence that were previously sent can be resend (from the internal sender-side cache of sent messages in a sequence) as follows:</p>
<div class="fragment"><div class="line"><a class="code" href="wsrmapi_8h.html#af0644e93628d1c450cb3c73fed5afd4f">soap_wsrm_resend</a>(soap, seq, 0, 0);</div></div><!-- fragment --><p>To resend a range of non-acknowledged messages, say between 3 and 7, use:</p>
<div class="fragment"><div class="line"><a class="code" href="wsrmapi_8h.html#af0644e93628d1c450cb3c73fed5afd4f">soap_wsrm_resend</a>(soap, seq, 3, 7);</div></div><!-- fragment --><p>Or all messages after message number 3:</p>
<div class="fragment"><div class="line"><a class="code" href="wsrmapi_8h.html#af0644e93628d1c450cb3c73fed5afd4f">soap_wsrm_resend</a>(soap, seq, 3, 0);</div></div><!-- fragment --><p>Resends should be used with care, since in the worst case when no acknowledgements have been received all messages up to the last will be resend (and ignored by the WS-RM destination when a message is received more than once).</p>
<p>Note that when an AcksTo destination service address was set with <code>soap_wsrm_create</code> or <code>soap_wsrm_create_offer</code>, then the acknowledgements will not be returned to the sender (client). In this case message resends are performed for all messages sent, since these have not been acknowledged.</p>
<p>It is permitted to issue resends between creation and termination of a sequence, including after a sequence close (as long as no new messages are sent after close). The sequence close provides acknowledgement information to limit the number of messages that need to be resend.</p>
<p>To find out if none, some, or all messages have been acknowledged, use:</p>
<div class="fragment"><div class="line">ULONG64 nack = <a class="code" href="wsrmapi_8h.html#a5a6aec6d79f12deef6b60e878a7c3dc9">soap_wsrm_nack</a>(seq);</div><div class="line"><span class="keywordflow">if</span> (nack == 0)</div><div class="line">  ... <span class="comment">// all sent messages have been acknowledged</span></div><div class="line"><span class="keywordflow">else</span> <span class="keywordflow">if</span> (nack == <a class="code" href="wsrmapi_8h.html#a7c22db1671c488e9eef77d5f55b687e7">soap_wsrm_num</a>(seq))</div><div class="line">  ... <span class="comment">// none of the sent messages have been acknowledged</span></div><div class="line"><span class="keywordflow">else</span></div><div class="line">  ... <span class="comment">// some sent messages have been acknowledged</span></div></div><!-- fragment --><h2><a class="anchor" id="wsrm_4_6"></a>
Relaying Response and Fault Messages with WS-Addressing</h2>
<p>WS-ReliableMessaging is important when messages are relayed, and especially when relayed over UDP.</p>
<p>The ReplyTo and FaultTo destination service endpoints can be specified for each message as follows:</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *replyto = source; <span class="comment">// endpoint of WS-RM source</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *faultto = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// endpoint of fault processing service</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *endpoint = <a class="code" href="wsrmapi_8h.html#abd9ac0c9258d6f2210d767aeff3cbf51">soap_wsrm_to</a>(seq);</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (endpoint)</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a7292b4a8e24e767b538e0fb2993a6864">soap_wsrm_request_acks</a>(soap, seq, NULL, exampleRequestAction)</div><div class="line">   || <a class="code" href="wsaapi_8h.html#a8b4871953a687b6f360b04c4bddeb49c">soap_wsa_add_ReplyTo</a>(soap, replyto)</div><div class="line">   || <a class="code" href="wsaapi_8h.html#afc91d81e9eec6b9bc39efbd5e715a18a">soap_wsa_add_FaultTo</a>(soap, faultto))</div><div class="line">    ... <span class="comment">// error: out of memory</span></div><div class="line">  <span class="keywordflow">if</span> (soap_call_ns__example(soap, endpoint, exampleRequestAction, &amp;response))</div><div class="line">  {</div><div class="line">    <span class="keywordflow">if</span> (soap-&gt;error != 202)</div><div class="line">      ... <span class="comment">// error</span></div><div class="line">  }</div><div class="line">}</div></div><!-- fragment --><p>An optional source address information header can be added with <code>soap_wsa_add_From</code>:</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *from = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// endpoint of the client (could be any URI)</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a7292b4a8e24e767b538e0fb2993a6864">soap_wsrm_request_acks</a>(soap, seq, NULL, exampleRequestAction)</div><div class="line"> || <a class="code" href="wsaapi_8h.html#a173c7beac1825c49f5d3b446ccdbc6b8">soap_wsa_add_From</a>(soap, from))</div><div class="line">  ... <span class="comment">// error: out of memory</span></div></div><!-- fragment --><p>Adding a From address is optional and usually not required with WS-ReliableMessaging.</p>
<h2><a class="anchor" id="wsrm_4_7"></a>
Using Retry Loops to Improve Robustness of Message Sends</h2>
<p>A potential problem with reliable message delivery with resends can fail when the initial send was not successful and message ordering is relevant. Resending will lead to an unordered message delivery.</p>
<p>Also, the wsrm plugin records all sent messages when the send operation was not interrupted. A problem occurs when the message cache contains incomplete messages and these messages cannot be resend. This section presents an additional mechanism to ensure messages are cached properly for automatic retransmission.</p>
<p>Besides network failues, a request-response message exchange can also appear to fail due to a non <code>SOAP_OK</code> returned, such as a benign "HTTP 202 Accept" To distinguish fatal send errors from errors returned by the peer, the <code>soap_wsrm_check_retry</code> function can be used as follows to only retry the message exchange (or send) when needed:</p>
<div class="fragment"><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *endpoint = NULL;</div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a7292b4a8e24e767b538e0fb2993a6864">soap_wsrm_request_acks</a>(soap, seq, NULL, exampleRequestAction))</div><div class="line">  ... <span class="comment">// error</span></div><div class="line"><span class="keywordflow">while</span> ((endpoint = <a class="code" href="wsrmapi_8h.html#abd9ac0c9258d6f2210d767aeff3cbf51">soap_wsrm_to</a>(seq)) != NULL &amp;&amp; soap_call_ns__example(soap, endpoint, exampleRequestAction, &amp;response))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error == 202)</div><div class="line">  {</div><div class="line">    <span class="comment">// request was accepted by destination (HTTP 202 Accept)</span></div><div class="line">    <span class="keywordflow">break</span>;</div><div class="line">  }</div><div class="line">  <span class="keywordflow">else</span> <span class="keywordflow">if</span> (soap-&gt;error == SOAP_NO_TAG) <span class="comment">// empty &lt;Body&gt;</span></div><div class="line">  {</div><div class="line">    <span class="comment">// request was accepted by destination, acks are returned</span></div><div class="line">    <span class="keywordflow">break</span>;</div><div class="line">  }</div><div class="line">  soap_print_fault(soap, stderr);</div><div class="line">  <span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a091a66f982799656bf39cf713ff29eff">soap_wsrm_check_retry</a>(soap, seq))</div><div class="line">    <span class="keywordflow">break</span>; <span class="comment">// do not continue</span></div><div class="line">  sleep(1); <span class="comment">// wait a second to give network a chance to recover</span></div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (soap-&gt;error == SOAP_OK)</div><div class="line">  ... <span class="comment">// response can be processed</span></div></div><!-- fragment --><p>Note that the <code>soap_wsrm_request</code> is only invoked once in the above to increment the message enumeration.</p>
<p>The loop retries transmissions a maximum of <code>SOAP_WSRM_MAX_RETRIES</code> iterations before giving up.</p>
<p>Note that this mechanism does not replace acknowledgements for delivery. Delivery acknowledgements are verified with <code>soap_wsrm_nack</code>.</p>
<h2><a class="anchor" id="wsrm_4_8"></a>
Example Client</h2>
<p>The following code shows an example WS-RM client fragment that combines the concepts introduced in the previous sections for a request-response scenario:</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>soap *soap = soap_new(); <span class="comment">// Note: can use C++ proxy instead of &#39;soap&#39;</span></div><div class="line">soap_register_plugin(soap, <a class="code" href="wsaapi_8h.html#aa013e3760b97c2efcc71d29b57394501">soap_wsa</a>);</div><div class="line">soap_register_plugin(soap, <a class="code" href="wsrmapi_8h.html#a3ca1614f5da3589a41957cb2f93394dc">soap_wsrm</a>);</div><div class="line"></div><div class="line"><span class="keyword">struct </span>ns__exampleResponse response;</div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *exampleRequestAction = <span class="stringliteral">&quot;urn:example/examplePort/example&quot;</span>;</div><div class="line"></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *destination = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// WS-RM destination server address</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *source = NULL;       <span class="comment">// WS-RM source (current)</span></div><div class="line">ULONG64 expires = 60000;         <span class="comment">// 1 minute sequence lifetime</span></div><div class="line"></div><div class="line"><a class="code" href="structsoap__wsrm__sequence.html">soap_wsrm_sequence_handle</a> seq;</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a54cb27e4c3139e5197a30d15686cadca">soap_wsrm_create_offer</a>(soap, destination, source, NULL, expires, <a class="code" href="wsrm_8h.html#aff9cd7eafbe766f7c92b26f868cb0418aa8b0ffb8243f515937e5e229bb3d9be3">DiscardEntireSequence</a>, NULL, &amp;seq))</div><div class="line">{</div><div class="line">  <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">  ... <span class="comment">// error creating sequence</span></div><div class="line">} </div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a7292b4a8e24e767b538e0fb2993a6864">soap_wsrm_request_acks</a>(soap, seq, NULL, exampleRequestAction))</div><div class="line">  ... <span class="comment">// error</span></div><div class="line"><span class="keywordflow">while</span> (soap_call_ns__example(soap, destination, exampleRequestAction, &amp;response))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error == 202)</div><div class="line">  {</div><div class="line">    <span class="comment">// request was accepted by destination (HTTP 202 Accept)</span></div><div class="line">    <span class="keywordflow">break</span>;</div><div class="line">  }</div><div class="line">  <span class="keywordflow">else</span> <span class="keywordflow">if</span> (soap-&gt;error == SOAP_NO_TAG) <span class="comment">// empty &lt;Body&gt;</span></div><div class="line">  {</div><div class="line">    <span class="comment">// request was accepted by destination, acks are returned</span></div><div class="line">    <span class="keywordflow">break</span>;</div><div class="line">  }</div><div class="line">  soap_print_fault(soap, stderr);</div><div class="line">  <span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a091a66f982799656bf39cf713ff29eff">soap_wsrm_check_retry</a>(soap, seq))</div><div class="line">    <span class="keywordflow">break</span>; <span class="comment">// do not continue</span></div><div class="line">  sleep(1); <span class="comment">// wait a second to give network a chance to recover</span></div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (soap-&gt;error == SOAP_OK)</div><div class="line">  ... <span class="comment">// response can be processed</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a663e39e46e4fb291ee0f9af8a0badac5">soap_wsrm_close</a>(soap, seq, NULL))</div><div class="line">{</div><div class="line">  <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">  ... <span class="comment">// error closing sequence</span></div><div class="line">} </div><div class="line"></div><div class="line"><a class="code" href="wsrmapi_8h.html#af0644e93628d1c450cb3c73fed5afd4f">soap_wsrm_resend</a>(soap, seq, 0, 0); <span class="comment">// resend non-acked messages</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#aed55a951561e63b74699003f423e6e4d">soap_wsrm_terminate</a>(soap, seq, NULL))</div><div class="line">{</div><div class="line">  <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">  ... <span class="comment">// error</span></div><div class="line">} </div><div class="line"></div><div class="line"><a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line"></div><div class="line">soap_destroy(soap);</div><div class="line">soap_end(soap);</div><div class="line">soap_free(soap);</div></div><!-- fragment --><p>A duplex mode client that accepts responses via a callback:</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>soap *soap = soap_new(); <span class="comment">// Note: can use C++ proxy instead of &#39;soap&#39;</span></div><div class="line">soap_register_plugin(soap, <a class="code" href="wsaapi_8h.html#aa013e3760b97c2efcc71d29b57394501">soap_wsa</a>);</div><div class="line">soap_register_plugin(soap, <a class="code" href="wsrmapi_8h.html#a3ca1614f5da3589a41957cb2f93394dc">soap_wsrm</a>);</div><div class="line"></div><div class="line"><span class="keyword">struct </span>ns__exampleResponse response;</div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *exampleRequestAction = <span class="stringliteral">&quot;urn:example/examplePort/example&quot;</span>;</div><div class="line"></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *destination = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// WS-RM destination server address</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *source = <span class="stringliteral">&quot;...&quot;</span>;      <span class="comment">// WS-RM source address destination sends to</span></div><div class="line"><span class="keywordtype">int</span> source_port = ...;           <span class="comment">// port of WS-RM source address</span></div><div class="line">ULONG64 expires = 60000;         <span class="comment">// 1 minute sequence lifetime</span></div><div class="line"><span class="keywordtype">int</span> retry;</div><div class="line"></div><div class="line"><a class="code" href="structsoap__wsrm__sequence.html">soap_wsrm_sequence_handle</a> seq;</div><div class="line"></div><div class="line"><span class="keyword">struct </span>soap *callback = soap_new(); <span class="comment">// callback for polling</span></div><div class="line"></div><div class="line"><span class="comment">// WS-RM source port binding for the callback to poll messages</span></div><div class="line"><span class="keywordflow">if</span> (!soap_valid_socket(soap_bind(callback, NULL, source_port, 100)))</div><div class="line">  ... <span class="comment">// error</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a54cb27e4c3139e5197a30d15686cadca">soap_wsrm_create_offer</a>(soap, destination, source, NULL, expires, <a class="code" href="wsrm_8h.html#aff9cd7eafbe766f7c92b26f868cb0418aa8b0ffb8243f515937e5e229bb3d9be3">DiscardEntireSequence</a>, NULL, &amp;seq))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error != 202)</div><div class="line">  {</div><div class="line">    <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">    ... <span class="comment">// error creating sequence</span></div><div class="line">  }</div><div class="line">} </div><div class="line"></div><div class="line"><span class="comment">// poll 10 times for 1 second until the sequence created response received</span></div><div class="line"><span class="keywordflow">for</span> (retry = 10; retry &amp;&amp; !<a class="code" href="wsrmapi_8h.html#a9029b22721a4b39c0c7ef22b53de0900">soap_wsrm_seq_created</a>(soap, seq); retry--)</div><div class="line">  <span class="keywordflow">if</span> (callback_poll(callback, 1)) <span class="comment">// 1 second poll</span></div><div class="line">    ... <span class="comment">// error</span></div><div class="line"><span class="keywordflow">if</span> (!retry)</div><div class="line">  ... <span class="comment">// error</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a7292b4a8e24e767b538e0fb2993a6864">soap_wsrm_request_acks</a>(soap, seq, NULL, exampleRequestAction))</div><div class="line">  ... <span class="comment">// error</span></div><div class="line"><span class="keywordflow">while</span> (soap_call_ns__example(soap, destination, exampleRequestAction, &amp;response))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error == 202)</div><div class="line">  {</div><div class="line">    <span class="comment">// request was accepted by destination (HTTP 202 Accept)</span></div><div class="line">    <span class="keywordflow">break</span>;</div><div class="line">  }</div><div class="line">  <span class="keywordflow">else</span> <span class="keywordflow">if</span> (soap-&gt;error == SOAP_NO_TAG) <span class="comment">// empty &lt;Body&gt;</span></div><div class="line">  {</div><div class="line">    <span class="comment">// request was accepted by destination, acks are returned</span></div><div class="line">    <span class="keywordflow">break</span>;</div><div class="line">  }</div><div class="line">  <span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a091a66f982799656bf39cf713ff29eff">soap_wsrm_check_retry</a>(soap, seq))</div><div class="line">    <span class="keywordflow">break</span>; <span class="comment">// do not continue</span></div><div class="line">  sleep(1); <span class="comment">// wait a second to give network a chance to recover</span></div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (callback_poll(callback, -500000)) <span class="comment">// 500 ms poll</span></div><div class="line">  ... <span class="comment">// error</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a663e39e46e4fb291ee0f9af8a0badac5">soap_wsrm_close</a>(soap, seq, NULL))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error != 202)</div><div class="line">  {</div><div class="line">    <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">    ... <span class="comment">// error closing sequence</span></div><div class="line">  }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// Resend messages marked as non-acked (as an option)</span></div><div class="line"><span class="keywordflow">for</span> (retry = 2; retry &amp;&amp; <a class="code" href="wsrmapi_8h.html#a5a6aec6d79f12deef6b60e878a7c3dc9">soap_wsrm_nack</a>(seq); retry--)</div><div class="line">{</div><div class="line">  <a class="code" href="wsrmapi_8h.html#af0644e93628d1c450cb3c73fed5afd4f">soap_wsrm_resend</a>(soap, seq, 0, 0); <span class="comment">// 0 0 means full range of msg nums</span></div><div class="line">  <span class="keywordflow">if</span> (callback_poll(callback, -500000)) <span class="comment">// 500 ms poll</span></div><div class="line">    ... <span class="comment">// error</span></div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#aed55a951561e63b74699003f423e6e4d">soap_wsrm_terminate</a>(soap, seq, NULL))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error != 202)</div><div class="line">  {</div><div class="line">    <a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line">    ... <span class="comment">// error closing sequence</span></div><div class="line">  }</div><div class="line">} </div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (callback_poll(callback, -500000)) <span class="comment">// 500 ms poll</span></div><div class="line">  ... <span class="comment">// error</span></div><div class="line"></div><div class="line"><a class="code" href="wsrmapi_8h.html#a21c32d0aaadf26d86170098a890c0e54">soap_wsrm_seq_free</a>(soap, seq);</div><div class="line"></div><div class="line">soap_destroy(callback);</div><div class="line">soap_end(callback);</div><div class="line">soap_free(callback);</div><div class="line">soap_destroy(soap);</div><div class="line">soap_end(soap);</div><div class="line">soap_free(soap);</div></div><!-- fragment --><h1><a class="anchor" id="wsrm_5"></a>
Server-side Usage</h1>
<p>To set up a WS-ReliableMessaging compliant server, register the wsa and wsrm plugins with the soap context (or with the C++ proxy object generated by soapcpp2 option <code>-j</code>):</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>soap *soap = soap_new(); <span class="comment">// Note: use C++ proxy-&gt;soap instead of &#39;soap&#39;</span></div><div class="line">soap_register_plugin(soap, <a class="code" href="wsaapi_8h.html#aa013e3760b97c2efcc71d29b57394501">soap_wsa</a>);</div><div class="line">soap_register_plugin(soap, <a class="code" href="wsrmapi_8h.html#a3ca1614f5da3589a41957cb2f93394dc">soap_wsrm</a>);</div></div><!-- fragment --><p>The following subsections detail the differences between the types of WS-RM destination services.</p>
<h2><a class="anchor" id="wsrm_5_1"></a>
Setting up a WS-RM Destination Service</h2>
<p>For duplex communications, it is advisable to send acknowledgements to the peer, which are normally piggy-backed on messages to the peer. If no messages are sent to the peer, explicit acknowledgements can be sent:</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#ac3fc1849fe2ecca83d6a5c95c314ecd3">soap_wsrm_acknowledgement</a>(soap, seq, NULL))</div><div class="line">  ... <span class="comment">// error</span></div></div><!-- fragment --><p>To sent acknowledgements to all peers with open sequences, use:</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> timeout = -10000; <span class="comment">// 10 ms</span></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#afb61518a4742df0e441dd100afd73693">soap_wsrm_pulse</a>(soap, timeout))</div><div class="line">  ... <span class="comment">// error</span></div></div><!-- fragment --><p>where timeout is in seconds (pos value) or microseconds (neg value). Depending on the message exchange scenarios, it may be advisable to have the server send periodic acknowledgement updates as follows:</p>
<div class="fragment"><div class="line">soap-&gt;accept_timeout = -200000; <span class="comment">// 200ms intervals</span></div><div class="line"><span class="keywordflow">for</span> (;;)</div><div class="line">{</div><div class="line">  <span class="comment">// server loop, accept next message</span></div><div class="line">  <span class="keywordflow">if</span> (!soap_valid_socket(accept()))</div><div class="line">  {</div><div class="line">    <span class="comment">// error or timeout?</span></div><div class="line">    <span class="keywordflow">if</span> (soap-&gt;errnum)</div><div class="line">    {</div><div class="line">      soap_stream_fault(std::cerr);</div><div class="line">      exit(1); <span class="comment">// may want to exit, but trying to continue is also possible</span></div><div class="line">    }</div><div class="line">    <span class="keywordflow">else</span></div><div class="line">    {</div><div class="line">      <span class="comment">// timeout occurs after 200ms</span></div><div class="line">      <span class="comment">// send acks to peers (optional), take 10 ms per message </span></div><div class="line">      <a class="code" href="wsrmapi_8h.html#afb61518a4742df0e441dd100afd73693">soap_wsrm_pulse</a>(soap, -10000); <span class="comment">// 10 ms</span></div><div class="line">      <span class="comment">// sleep(1); // must do this with UDP: since accept() returns immediately</span></div><div class="line">    }</div><div class="line">  }</div><div class="line">  <span class="keywordflow">else</span></div><div class="line">  {</div><div class="line">    ... <span class="comment">// serve</span></div><div class="line">  }</div></div><!-- fragment --><p>Each service operation that supports WS-ReliableMessaging and WS-Addressing should use the <code>soap_wsrm_check</code>, <code>soap_wsrm_sender_fault</code>, <code>soap_wsrm_receiver_fault</code>, and <code>soap_wsrm_reply</code> functions as follows:</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> ns__example(<span class="keyword">struct</span> soap *soap, <span class="keywordtype">char</span> *in, <span class="keyword">struct</span> ns__exampleResponse *response)</div><div class="line">{</div><div class="line">  <span class="keyword">const</span> <span class="keywordtype">char</span> *ResponseAction = <span class="stringliteral">&quot;urn:example/examplePort/exampleResponse&quot;</span>;</div><div class="line"></div><div class="line">  <span class="comment">// fatal service operation-specific errors (before soap_wsrm_check())</span></div><div class="line">  <span class="keywordflow">if</span> (!database) <span class="comment">// suppose we need a database, if there is none terminate</span></div><div class="line">    <span class="keywordflow">return</span> <a class="code" href="wsrmapi_8h.html#a65c7a86eaf7366b9cb9c4759c1f7c061">soap_wsrm_receiver_fault</a>(soap, <span class="stringliteral">&quot;No database!&quot;</span>, NULL);</div><div class="line"></div><div class="line">  <span class="comment">// check for WS-RM/WSA and set WS-RM/WSA return headers and protocol errors</span></div><div class="line">  <span class="comment">// note: use soap_wsrm_check_and_wait() with NoDiscard behavior to queue out-of-order messages</span></div><div class="line">  <span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a0304e1219b99929fa576cf12114206eb">soap_wsrm_check</a>(soap))</div><div class="line">    <span class="keywordflow">return</span> soap-&gt;error;</div><div class="line"></div><div class="line">  <span class="comment">// check for non-fatal service operation-specific errors</span></div><div class="line">  <span class="keywordflow">if</span> (!in || !*in) <span class="comment">// sender did not put anything in the &#39;in&#39; string: fault</span></div><div class="line">    <span class="keywordflow">return</span> <a class="code" href="wsrmapi_8h.html#af2bcd68f3810d632bef61ecfe86e1e5f">soap_wsrm_sender_fault</a>(soap, <span class="stringliteral">&quot;No string content!&quot;</span>, NULL);</div><div class="line"></div><div class="line">  response-&gt;out = ...</div><div class="line"></div><div class="line">  <span class="comment">// return normally, relaying the response to the ReplyTo service when needed</span></div><div class="line">  <span class="keywordflow">return</span> <a class="code" href="wsrmapi_8h.html#af7ab54d15beca0118bdffc64520b6589">soap_wsrm_reply</a>(soap, NULL, ResponseAction);</div><div class="line">}</div></div><!-- fragment --><p>An error produced by <code>soap_wsrm_sender_fault</code> or <code>soap_wsrm_receiver_fault</code> before <code>soap_wsrm_check</code> is considered fatal, it will terminate the sequence and the sender (client) will not be able to continue the sequence transmissions. While the faults preduced after <code>soap_wsrm_check</code> allow the sequence to continue.</p>
<h2><a class="anchor" id="wsrm_5_2"></a>
Handling Duplex Callback Service Operations</h2>
<p>To set up a callback to accept responses in a duplex scenario, we set up the server in the same way as the destination server. Service opertions should not use <code>soap_wsrm_reply</code>. Because response messages are sent (as if these were request messages), the service must define the appropriate one-way operations and gSOAP service definitions bindings.</p>
<p>For example, the one-way response message of the ns__example operation is defined as follows in the gSOAP service definitions header file:</p>
<div class="fragment"><div class="line"><span class="comment">//gsoap ns service method-header-part: exampleResponse wsa5__MessageID</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: exampleResponse wsa5__RelatesTo</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: exampleResponse wsa5__From</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: exampleResponse wsa5__ReplyTo</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: exampleResponse wsa5__FaultTo</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: exampleResponse wsa5__To</span></div><div class="line"><span class="comment">//gsoap ns service method-header-part: exampleResponse wsa5__Action</span></div><div class="line"></div><div class="line"><span class="comment">//gsoap ns service method-header-part: exampleResponse wsrm__SequenceAcknowledgement</span></div><div class="line"></div><div class="line"><span class="comment">//gsoap ns service method-action: exampleResponse urn:example/examplePort/exampleResponse</span></div><div class="line"></div><div class="line"><span class="keywordtype">int</span> ns__exampleResponse(<span class="keywordtype">char</span> *out, <span class="keywordtype">void</span>);</div></div><!-- fragment --><p>The one-way response service operations are automatically generated with wsdl2h option <code>-b</code>.</p>
<p>Note that when these definitions are combined with the previous definition for <code>ns__example</code>, there is no need to define the <code>ns__ExampleResponse</code> struct any longer as this is implied by the <code>ns__exampleResponse</code> function content.</p>
<p>The server operation implementation is for example:</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> ns__exampleResponse(<span class="keyword">struct</span> soap *soap, <span class="keywordtype">char</span> *out)</div><div class="line">{</div><div class="line">  <span class="comment">// check WS-RM/WSA headers and protocol errors and send 202 Accept back to peer</span></div><div class="line">  <span class="comment">// note: use soap_wsrm_check_send_empty_response_and_wait() with NoDiscard behavior to queue out-of-order messages</span></div><div class="line">  <span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a610fc6b7362861887d5f50c949e12818">soap_wsrm_check_send_empty_response</a>(soap))</div><div class="line">    <span class="keywordflow">return</span> soap-&gt;error;</div><div class="line">  ... <span class="comment">// process the &#39;out&#39; content, invoke callback etc</span></div><div class="line">  <span class="keywordflow">return</span> SOAP_OK;</div><div class="line">}</div></div><!-- fragment --><h1><a class="anchor" id="wsrm_6"></a>
WS-ReliableMessaging over HTTPS with Basic Authentication</h1>
<p>The HTTPS client and server are set up as shown in the gSOAP documentation and examples. There are no additional API calls needed to support WS-RM with HTTPS.</p>
<p>Note that the WS-RM destination service may also relay messages to other HTTPS services, thus the WS-RM destination acts as a receiver (server) and sender (client). Therefore, the WS-RM destination server's SSL context should be set to authenticate the other servers:</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (soap_ssl_server_context(soap,</div><div class="line">  SOAP_SSL_DEFAULT,</div><div class="line">  <span class="stringliteral">&quot;server.pem&quot;</span>,     <span class="comment">// keyfile (server)</span></div><div class="line">  <span class="stringliteral">&quot;password&quot;</span>,       <span class="comment">// password to read the key file (server)</span></div><div class="line">  <span class="stringliteral">&quot;cacert.pem&quot;</span>,     <span class="comment">// cacert file to store trusted certificates (client)</span></div><div class="line">  NULL,             <span class="comment">// optional capath</span></div><div class="line">  NULL,     <span class="comment">// DH file name or DH param key len bits, NULL: RSA</span></div><div class="line">  NULL,             <span class="comment">// file with random data to seed randomness</span></div><div class="line">  argv[1]   <span class="comment">// unique server identification for SSL session cache</span></div><div class="line">))</div><div class="line">{</div><div class="line">  soap_print_fault(soap, stderr);</div><div class="line">  ... <span class="comment">// handle error</span></div><div class="line">}</div></div><!-- fragment --><p>Here, the cacert.pem file contains certificates to authenticate the ReplyTo, FaultTo, and AcksTo services when HTTPS is used.</p>
<p>The client side sets up the SSL context with the <code>soap_ssl_client_context</code> as instructed in the documentation and by the examples. Multi-threaded HTTPS clients and servers must register mutex locks with OpenSSL</p>
<p>To use Basic Authentication at the client side, set the userid and passwd values:</p>
<div class="fragment"><div class="line">soap-&gt;userid = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// Basic Auth user id</span></div><div class="line">soap-&gt;passwd = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// Basic Auth password</span></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a7292b4a8e24e767b538e0fb2993a6864">soap_wsrm_request_acks</a>(soap, seq, NULL, exampleRequestAction)</div><div class="line">  ... <span class="comment">// error: out of memory</span></div><div class="line"><span class="keywordflow">if</span> (soap_call_ns__example(soap, endpoint, exampleRequestAction, &amp;response))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error == 401)</div><div class="line">    ... <span class="comment">// authentication failed for the userid/passwd pair</span></div><div class="line">  else</div><div class="line">    ... <span class="comment">// other error</span></div><div class="line">}</div></div><!-- fragment --><p>At the server side add the authentication check to the service operation before <code>soap_wsrm_check</code> to terminate the sequence when an authentication failure occurs. For example:</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> ns__example(<span class="keyword">struct</span> soap *soap, <span class="keywordtype">char</span> *in, <span class="keyword">struct</span> ns__exampleResponse *response)</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (!soap-&gt;userid || !soap-&gt;passwd || strcmp(soap-&gt;userid, <span class="stringliteral">&quot;...&quot;</span>) || strcmp(soap-&gt;passwd, <span class="stringliteral">&quot;...&quot;</span>))</div><div class="line">  {</div><div class="line">    soap-&gt;authrealm = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// optional to set HTTP WWW-Authenticate: Basic realm=&quot;...&quot;</span></div><div class="line">    <span class="keywordflow">return</span> 401; <span class="comment">// HTTP 401 Unauthorized</span></div><div class="line">  }</div><div class="line">  <span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a0304e1219b99929fa576cf12114206eb">soap_wsrm_check</a>(soap))</div><div class="line">    <span class="keywordflow">return</span> soap-&gt;error;</div><div class="line">  ...</div></div><!-- fragment --><p>Here, we check only one userid-passwd pair though normally we could search for valid credentials in an authentication store.</p>
<p>Note: never use Basic Authentication over HTTP because the password is sent in the clear. You must use HTTPS to encrypt the HTTP authentication information and message content. HTTP Digest Auth is preferred for this reason, because Digest Auth verifies the digest of a userid-passwd rather than require the password to be exchanged or stored in cleartext.</p>
<h1><a class="anchor" id="wsrm_7"></a>
WS-ReliableMessaging over UDP with Timeouts</h1>
<p>The use of UDP is automatic at the client side using the "soap.udp://" protocol. Therefore, endpoints should use a "soap.udp://" URL to connect. (when using an already opened socket, the <code>SOAP_IO_UDP</code> flag must be used, see the documentation.)</p>
<p>Note that UDP datagram messages should not exceed 8K, which is usually a size that UDP datagrams can support. To reduce the message size, we recommend compression (<code>-DWITH_GZIP</code> compile flag to enable ZLIB and use libgsoapssl.a or libgsoapssl++.a for OpenSSL and ZLIB compression combined).</p>
<p>The code of an UDP-enabled server is identical to an HTTP/TCP server except that the <code>soap_accept</code> call is disabled and unnecessary.</p>
<p>When message responses are not returned to the client, the client may block indefinitely when it expects a response. Therefore we recommend the use of send and receive timeouts:</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>soap *soap = soap_new();</div><div class="line"></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *destination = <span class="stringliteral">&quot;soap.udp://...&quot;</span>;</div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *source = NULL;</div><div class="line">ULONG64 expires = 60000;         <span class="comment">// 1 minute sequence lifetime</span></div><div class="line"></div><div class="line">soap-&gt;send_timeout = soap-&gt;recv_timeout = 1; <span class="comment">// 1 second to timeout</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a54cb27e4c3139e5197a30d15686cadca">soap_wsrm_create_offer</a>(soap, destination, source, NULL, expires, <a class="code" href="wsrm_8h.html#aff9cd7eafbe766f7c92b26f868cb0418a1a5ed0390b355179aad4c5e99024a1e1">NoDiscard</a>, NULL, &amp;seq))</div><div class="line"> ... <span class="comment">// an error occured</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a05857d4bed3b3052e6878f490330277f">soap_wsrm_request</a>(soap, seq, NULL, exampleRequestAction))</div><div class="line">  ... <span class="comment">// an error occured</span></div><div class="line"><span class="keywordflow">if</span> (soap_call_ns__example(soap, ...))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error == SOAP_EOF &amp;&amp; soap-&gt;errnum == 0)</div><div class="line">    ... <span class="comment">// a timeout occured</span></div><div class="line">  <span class="keywordflow">else</span></div><div class="line">    ... <span class="comment">// an error occured</span></div><div class="line">}</div></div><!-- fragment --><p>Note that the WS-Addressing ReplyTo and the use of NoReply do not return response message from the server. However, acknowledgements will be returned when acknowledgements were requested (unless acknowledgements are relayed with AcksTo).</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>soap *soap = soap_new();</div><div class="line"></div><div class="line">soap-&gt;send_timeout = soap-&gt;recv_timeout = 1; <span class="comment">// 1 second to timeout</span></div><div class="line"></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *destination = <span class="stringliteral">&quot;soap.udp://...&quot;</span>;</div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *from = <span class="stringliteral">&quot;...&quot;</span>; <span class="comment">// some identifying URI</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">char</span> *source = from;</div><div class="line">ULONG64 expires = 60000;         <span class="comment">// 1 minute sequence lifetime</span></div><div class="line"></div><div class="line">soap-&gt;send_timeout = soap-&gt;recv_timeout = 1; <span class="comment">// 1 second to timeout</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a54cb27e4c3139e5197a30d15686cadca">soap_wsrm_create_offer</a>(soap, destination, source, NULL, expires, <a class="code" href="wsrm_8h.html#aff9cd7eafbe766f7c92b26f868cb0418a1a5ed0390b355179aad4c5e99024a1e1">NoDiscard</a>, NULL, &amp;seq))</div><div class="line"> ... <span class="comment">// an error occured</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (<a class="code" href="wsrmapi_8h.html#a7292b4a8e24e767b538e0fb2993a6864">soap_wsrm_request_acks</a>(soap, seq, NULL, exampleRequestAction)</div><div class="line"> || <a class="code" href="wsaapi_8h.html#a18abaa4aba0f1bf391fbd2152070faae">soap_wsa_add_NoReply</a>(soap)</div><div class="line">  ... <span class="comment">// an error occured</span></div><div class="line"><span class="keywordflow">if</span> (soap_call_ns__example(soap, ...))</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (soap-&gt;error == SOAP_EOF &amp;&amp; soap-&gt;errnum == 0)</div><div class="line">    ... <span class="comment">// a timeout occured</span></div><div class="line">  <span class="keywordflow">else</span> if (soap-&gt;error == SOAP_NO_TAG)</div><div class="line">    ... <span class="comment">// ack was received and recorded</span></div><div class="line">  else</div><div class="line">    ... <span class="comment">// an error occured</span></div><div class="line">}</div></div><!-- fragment --><p>In this case an acknowledgement will be returned and the timeout reflects a possible network packet loss.</p>
<h1><a class="anchor" id="wsrm_8"></a>
WS-ReliableMessaging and WS-Security</h1>
<p>WS-Security can be combined with WS-ReliableMessaging using the <a href="../../wsse/html/index.html">WS-Security plugin</a>.</p>
<p>Both plugins must be registered at the client and server side. These APIs are independent.</p>
<h1><a class="anchor" id="wsrm_9"></a>
The wsrm Plugin and C++ Proxy and Server Objects</h1>
<p>The WS-ReliableMessaging plugin is developed to support C and C++. To support C++ server objects generated with soapcpp2 option <code>-j</code> (or <code>-i</code>), run soapcpp2 again: </p><pre class="fragment">soapcpp2 -A -pwsrx import/wsrx.h
</pre><p>This generates wsrxClient.cpp and wsrxServer.cpp that are also needed with the WS-ReliableMessaging plugin and code.</p>
<p>To dispatch the wsrm service operations when received: Suppose we have a myService server class generated by soapcpp2 option <code>-j</code>, which is used to process requests with the serve() member function (also generated):</p>
<div class="fragment"><div class="line">myService service;</div><div class="line"><span class="keywordflow">if</span> (soap_invalid_socket(service.bind(NULL, port, 100)))</div><div class="line">  ... <span class="comment">// error</span></div><div class="line"><span class="keywordflow">for</span> (;;)</div><div class="line">{</div><div class="line">  <span class="keywordflow">if</span> (!soap_valid_socket(service.accept()))</div><div class="line">  {</div><div class="line">    service.soap_stream_fault(std::cerr);</div><div class="line">    exit(1);</div><div class="line">  }</div><div class="line">  <span class="keywordflow">if</span> (soap_begin_serve(service.soap) == SOAP_OK)</div><div class="line">  {</div><div class="line">    <span class="keywordflow">if</span> (service.dispatch() == SOAP_NO_METHOD)</div><div class="line">    {</div><div class="line">      <span class="keywordflow">if</span> (soap_serve_request(service.soap) != SOAP_OK)</div><div class="line">      {</div><div class="line">        soap_send_fault(service.soap);</div><div class="line">        service.soap_stream_fault(std::cerr);</div><div class="line">      }</div><div class="line">    }</div><div class="line">    <span class="keywordflow">else</span> <span class="keywordflow">if</span> (service.soap-&gt;error)</div><div class="line">      service.soap_stream_fault(std::cerr);</div><div class="line">  }</div><div class="line">  service.destroy();</div><div class="line">}</div></div><!-- fragment --><h1><a class="anchor" id="wsrm_10"></a>
Speed improvements with large number of sequences</h1>
<p>Compile <a class="el" href="wsrmapi_8c.html">wsrmapi.c</a> with <code>-DSOAP_WSRM_FAST_LOOKUP</code> to speed up sequence lookups for a large number of concurrent message sequences or sequences with a long time to live. An internal hash table is used, which will grow to accommodate the total number of concurrent sequences. The hash table entries are reused but (temporary) empty entries are never deallocated to avoid allocation overhead, which means that leak detectors may complain about space not being freed. </p>
</div></div><!-- contents -->
<hr class="footer">
<address class="footer">
Copyright (C) 2018, Robert van Engelen, Genivia Inc., All Rights Reserved.
</address>
<address class="footer"><small>
Converted on Sun Dec 9 2018 16:27:25 by <a target="_blank" href="http://www.doxygen.org/index.html">Doxygen</a> 1.8.11</small></address>
<br>
<div style="height: 246px; background: #DBDBDB;">
</body>
</html>
